#include "kernel.h"
extern "C"{
void kerneltwo(
		IN_TYPE offset1[OFFSET_LEN],IN_TYPE adj1[ADJ_LEN],
		IN_TYPE offset2[OFFSET_LEN],IN_TYPE adj2[ADJ_LEN],
		IN_TYPE offset3[OFFSET_LEN],IN_TYPE adj3[ADJ_LEN],
		IN_TYPE offset4[OFFSET_LEN],IN_TYPE adj4[ADJ_LEN],
		IN_TYPE cand1[CAN_LEN],CAN_TYPE cand2[CAN2_LEN],
		IN_TYPE size1,IN_TYPE size2,
		IN_TYPE pid1,IN_TYPE pid2,
		IN_TYPE out_buf[OUT_LEN]
		)
{
#pragma HLS INTERFACE m_axi port=cand1 offset=slave bundle=gmem0
#pragma HLS INTERFACE m_axi port=cand2 offset=slave bundle=gmem1
#pragma HLS INTERFACE m_axi port=out_buf offset=slave bundle=gmem2

#pragma HLS INTERFACE m_axi port=offset1 offset=slave bundle=gmem3
#pragma HLS INTERFACE m_axi port=adj1 offset=slave bundle=gmem4
#pragma HLS INTERFACE m_axi port=offset2 offset=slave bundle=gmem5
#pragma HLS INTERFACE m_axi port=adj2 offset=slave bundle=gmem6

#pragma HLS INTERFACE m_axi port=offset3 offset=slave bundle=gmem7
#pragma HLS INTERFACE m_axi port=adj3 offset=slave bundle=gmem8
#pragma HLS INTERFACE m_axi port=offset4 offset=slave bundle=gmem9
#pragma HLS INTERFACE m_axi port=adj4 offset=slave bundle=gmem10

#pragma HLS INTERFACE s_axilite port=offset1 bundle=control
#pragma HLS INTERFACE s_axilite port=adj1 bundle=control
#pragma HLS INTERFACE s_axilite port=offset2 bundle=control
#pragma HLS INTERFACE s_axilite port=adj2 bundle=control
#pragma HLS INTERFACE s_axilite port=offset3 bundle=control
#pragma HLS INTERFACE s_axilite port=adj3 bundle=control
#pragma HLS INTERFACE s_axilite port=offset4 bundle=control
#pragma HLS INTERFACE s_axilite port=adj4 bundle=control

#pragma HLS INTERFACE s_axilite port=cand1 bundle=control
#pragma HLS INTERFACE s_axilite port=cand2 bundle=control
#pragma HLS INTERFACE s_axilite port=out_buf bundle=control
#pragma HLS INTERFACE s_axilite port=size1 bundle=control
#pragma HLS INTERFACE s_axilite port=size2 bundle=control
#pragma HLS INTERFACE s_axilite port=pid1 bundle=control
#pragma HLS INTERFACE s_axilite port=pid2 bundle=control
#pragma HLS INTERFACE s_axilite port=return bundle=control
	IN_TYPE size_c1 = 0;
	IN_TYPE size_c2 = 0;
	static IN_TYPE preid1;
	static IN_TYPE preid2;
	//static IN_TYPE out_buffer[25600];
	static IN_TYPE cand1_buffer[1024][16];
#pragma HLS ARRAY_PARTITION variable=cand1_buffer complete dim=1
	//static IN_TYPE cand2_buffer[4][12500];
	//static IN_TYPE cand2_cache[99000];
//#pragma HLS RESOURCE variable=cand2_cache core=RAM_T2P_URAM
	static IN_TYPE cand1_count = 0;
	static IN_TYPE cand1_bf_count[1024];
#pragma HLS ARRAY_PARTITION variable=cand1_bf_count complete dim=1
	static IN_TYPE a1_count=0;
	static IN_TYPE a2_count=0;
	static IN_TYPE a1_cache[10000];
	static IN_TYPE a2_cache[10000];
	static IN_TYPE cand2_bf_count = 0;
	static IN_TYPE out_count=0;
	static IN_TYPE cand2_count = 0;
	static IN_TYPE out_iter = 0;
	IN_TYPE i,j,tmp,tmp2,begin,end,adj_size,iter,jj,kk,index,a1c,a2c,efcount,efoff;
	int bid,off;
	CAN_TYPE tmpblock,tmpblock2,tmpblock3;

	size_c1=0;
	size_c2=0;
	preid1=13;
	preid2=5;
	a1_count=0;
	a2_count=0;
	a1c=0;
	a2c=0;
	out_count=0;
	cand1_count=0;
	cand2_bf_count=0;
	out_iter=0;
	i=0;
	j=0;
	begin=0;
	end=0;
	adj_size=0;
	iter=0;
	jj=0;
	kk=0;
	index=0;
	size_c1 = size1;
	size_c2 = size2;
	preid1 = pid1;
	preid2 = pid2;

	for(;cand1_count<size1;){
		//cout<<"a new iteration"<<endl;
		INITIAL2:for(i=0;i<1024;i++){
			#pragma HLS UNROLL
			cand1_bf_count[i]=0;
		}
		CAND1_LOAD_OUTTER:for(i=0;i<1024 && cand1_count<size1;i++){
			tmp = cand1[cand1_count];
			cand1_count++;
			tmp2 = cand1[cand1_count];
			cand1_count++;
			cand1_buffer[i][0]=tmp;
			cand1_bf_count[i]++;
			cand1_buffer[i][1]=tmp2;
			cand1_bf_count[i]++;
			if(preid1==13){
				a1_count=0;
				a2_count=0;

				begin = offset2[tmp];
				end = offset2[tmp+1];
				adj_size = end - begin;
				READ_ADJ1:for(iter=0;iter<adj_size;iter++){
					a1_cache[a1_count++] = adj2[iter+begin];
					//cout<<a1_cache[a1_count-1]<<" ";
				}
				//cout<<endl;

				begin = offset1[tmp2];
				end = offset1[tmp2+1];
				adj_size = end - begin;
				READ_ADJ2:for(iter=0;iter<adj_size;iter++){
					a2_cache[a2_count++] = adj1[iter+begin];
					//cout<<a2_cache[a2_count-1]<<" ";
				}
				//cout<<endl;

				for(a1c = 0, a2c = 0; a1c < a1_count && a2c < a2_count;){
					if(a1_cache[a1c]>a2_cache[a2c]){
						a2c++;
					}else if(a1_cache[a1c]<a2_cache[a2c]){
						a1c++;
					}else{
						cand1_buffer[i][cand1_bf_count[i]] = a1_cache[a1c];
						//cout<<"finding commen element: "<<a1_cache[a1c]<<endl;
						a1c++;
						a2c++;
						cand1_bf_count[i]++;
					}
				}
			}else{
				a1_count=0;
				a2_count=0;

				begin = offset4[tmp];
				end = offset4[tmp+1];
				adj_size = end - begin;
				READ_ADJ3:for(iter=0;iter<adj_size;iter++){
					a1_cache[a1_count++] = adj4[iter+begin];
				}

				begin = offset3[tmp2];
				end = offset3[tmp2+1];
				adj_size = end - begin;
				READ_ADJ4:for(iter=0;iter<adj_size;iter++){
					a2_cache[a2_count++] = adj3[iter+begin];
				}

				for(a1c = 0, a2c = 0; a1c<a1_count && a2c < a2_count;){
					if(a1_cache[a1c]>a2_cache[a2c]){
						a2c++;
					}else if(a1_cache[a1c]<a2_cache[a2c]){
						a1c++;
					}else{
						cand1_buffer[i][cand1_bf_count[i]] = a1_cache[a1c];
						a1c++;
						a2c++;
						cand1_bf_count[i]++;
					}
				}
			}
		}

		for(i=0;i<1024;i++){
			for(jj=2;jj<cand1_bf_count[i];jj++){
				bid = cand1_buffer[i][jj] / 8;
				off = cand1_buffer[i][jj] % 8;
				tmpblock = cand2[bid];
				tmpblock2 = 1<<(7-off);
				//std::cout << "tmpblock is " << (int)tmpblock << " and tmpblock2 is " << (int)tmpblock2 << std::endl;
				tmpblock3 = tmpblock&tmpblock2;
				if(tmpblock3 == tmpblock2){
					out_buf[out_count++] = cand1_buffer[i][0];
					out_buf[out_count++] = cand1_buffer[i][1];
					out_buf[out_count++] = cand1_buffer[i][jj];
				}
			}
		}
	}
	efcount = out_count % 64;
	efoff = 64 - efcount + 1;
	for(i=0;i<efoff;i++){
		out_buf[out_count] = END_FLAG;
		out_count++;
	}
	//cout<<"out_size "<<out_count<<endl;
}
}

